#include "Task.hpp"
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include<iostream>

const int processnum =10;
std::vector<task_t> tasks;

class channel
{
public:
    channel(pid_t slaverid,int cmdfd,std::string processname)
        :_slaverid(slaverid),_cmdfd(cmdfd),_processname(processname)
    {}
public:
    pid_t  _slaverid; //子进程pid
    int _cmdfd;       //发送任务的文件描述符
    std::string _processname;//子进程名字
};

//子进程操作
void slaver()
{
    while(true)
    {
        int cmdcode = 0;
        int n = read(0,&cmdcode,sizeof(cmdcode));//读取4个字节
        if(n==sizeof(cmdcode))//每次读取到4个字节，就打印
        {
            std::cout <<"slaver say@ get a command: "<< getpid() << " : cmdcode: " <<  cmdcode << std::endl;
            if(cmdcode>=0&&cmdcode<tasks.size())
                tasks[cmdcode]();
        }
        if(n==0)
        {
            break;
        }
    }   
}

//初始化进程池
void InitProcessPool(std::vector<channel> *channels)
{
    std::vector<int> oldfds;
    for(int i = 0;i<processnum;i++)
    {
        //创建管道
        int pipefd[2];
        int n = pipe(pipefd);
        assert(!n);
        (void)n;

        pid_t id = fork();
        if(id<0)
            assert(id>=0);
        if(id == 0)
        {
            //子进程
            std::cout << "child: " << getpid() << " close history fd: ";

            // 把别人家的写端全关掉，避免我影响别人读 EOF
            for(auto fd : oldfds) 
            {
                std::cout << fd << " ";
                close(fd);
            }
            
            close(pipefd[1]);
            dup2(pipefd[0],0);//原来的读取输入端指向管道
            close(pipefd[0]);
            slaver();//子进程读操作的函数
            std::cout << "process : " << getpid() << " quit" << std::endl;
            exit(0);
        }
        //父进程
        close(pipefd[0]);
        //初始化channel
        std::string name = "process-" + std::to_string(i);//告诉用户这是第几个子进程
        channels->push_back(channel(id,pipefd[1],name));
        oldfds.push_back(pipefd[1]);
    }

}

void Menu()
{
    std::cout << "################################################" << std::endl;
    std::cout << "# 1. 刷新日志             2. 刷新出来野怪        #" << std::endl;
    std::cout << "# 3. 检测软件是否更新      4. 更新用的血量和蓝量  #" << std::endl;
    std::cout << "#                         0. 退出               #" << std::endl;
    std::cout << "#################################################" << std::endl;
}


void ctrlSlaver(const std::vector<channel> &channels)
{
    int which = 0;  //决定使用第几个线程
    while(true)
    {
        int select = 0; //给用户提供选项
        Menu();
        std::cout<<"please Enter"<<std::endl;
        std::cin>> select;
        if(select <= 0 || select >= 5) break;
        int cmdcode = select - 1; 

        std::cout << "father say: cmdcode: " << cmdcode 
          << " already sendto " << channels[which]._slaverid 
          << " process name: " << channels[which]._processname 
          << std::endl;

        write(channels[which]._cmdfd,&cmdcode,sizeof(cmdcode));//写入通道
        which++;
        which %= channels.size();
    }

}

void QuitProcess(const std::vector<channel> &channels)
{
    for(const auto &c : channels)
    {
        close(c._cmdfd);
        waitpid(c._slaverid, nullptr, 0);
    }
}


int main()
{
    
    LoadTask(&tasks);

    std::vector<channel> channels;
    InitProcessPool(&channels);//初始化
    ctrlSlaver(channels);//控制子进程
    QuitProcess(channels);
    return 0;
}